package com.qumitech.visualnovel.service.voiceRoom.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qumitech.visualnovel.component.util.CommonUtil;
import com.qumitech.visualnovel.component.util.DateUtil;
import com.qumitech.visualnovel.controller.vo.voiceRoom.VoiceRoomData;
import com.qumitech.visualnovel.controller.vo.voiceRoom.VoiceRoomStatisticDTO;
import com.qumitech.visualnovel.controller.vo.voiceRoom.VoiceRoomStatisticSearchConditionDTO;
import com.qumitech.visualnovel.datasource.console.*;
import com.qumitech.visualnovel.datasource.app.AccountMapper;
import com.qumitech.visualnovel.datasource.app.RobotConfigDOMapper;
import com.qumitech.visualnovel.datasource.app.VoiceRoomMapper;
import com.qumitech.visualnovel.model.dao.app.Account;
import com.qumitech.visualnovel.model.dao.console.StreamerDataDO;
import com.qumitech.visualnovel.model.dao.console.UserUpperVoiceRoomDO;
import com.qumitech.visualnovel.model.dao.app.VoiceRoom;
import com.qumitech.visualnovel.pubdef.dto.devicestatistic.DeviceStatisticDTO;
import com.qumitech.visualnovel.pubdef.dto.voiceroom.ConsoleVoiceRoomDataDTO;
import com.qumitech.visualnovel.pubdef.dto.voiceroom.ConsoleVoiceRoomChartDataDTO;
import com.qumitech.visualnovel.pubdef.dto.voiceroom.ConsoleVoiceRoomPieDataDTO;
import com.qumitech.visualnovel.pubdef.dto.voiceroom.query.VoiceRoomDataQueryDTO;
import com.qumitech.visualnovel.pubdef.dto.voiceroom.query.VoiceRoomUserUpperQueryDTO;
import com.qumitech.visualnovel.service.voiceRoom.VoiceRoomStatisticService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yilu
 * @date  2019/3/12 18:46
 */

@Service
public class VoiceRoomStatisticServiceImpl implements VoiceRoomStatisticService {

    @Autowired
    DateUtil dateUtil;

    @Autowired
    private VoiceRoomGiftDOMapper giftDOMapper;

    @Autowired
    private VoiceRoomUserDurationDOMapper userDurationDOMapper;

    @Autowired
    private StreamerDataDOMapper streamerDataDOMapper;

    @Autowired
    private UserUpperVoiceRoomDOMapper userUpperVoiceRoomDOMapper;

    @Autowired
    private VoiceRoomStatisticDOMapper voiceRoomStatisticDOMapper;

    @Autowired
    private UserLeaveVoiceRoomDOMapper userLeaveVoiceRoomDOMapper;

    @Autowired
    private UserGiftVoiceRoomDOMapper userGiftVoiceRoomDOMapper;

    @Autowired
    private RobotConfigDOMapper robotConfigDOMapper;

    @Autowired
    private VoiceRoomMapper voiceRoomMapper;

    @Autowired
    private AccountMapper accountMapper;

    private HashMap<String, Object> getTotalRoomNumAndBroadcastDuration(VoiceRoomStatisticSearchConditionDTO conditionDTO){
        return streamerDataDOMapper.getTotalRoomNumAndBroadcastDuration(conditionDTO);
    }

    private Long getIncreasedRoomNum(VoiceRoomStatisticSearchConditionDTO conditionDTO){
        return streamerDataDOMapper.getIncreasedRoomNum(conditionDTO);
    }

    private HashMap<String, Object> getTotalAccountInVoiceRoom(VoiceRoomStatisticSearchConditionDTO conditionDTO){
        return userDurationDOMapper.getTotalAccountInVoiceRoom(conditionDTO);
    }

    private HashMap<String, Object> getSendGiftInfo(VoiceRoomStatisticSearchConditionDTO conditionDTO){
        return giftDOMapper.getSendGiftInfo(conditionDTO);
    }

    @Override
    public List<ConsoleVoiceRoomDataDTO> getVoiceRoomData(VoiceRoomDataQueryDTO queryDTO) {
        String[] times = CommonUtil.setStartTime(queryDTO.getStartTime(), queryDTO.getEndTime());
        queryDTO.setStartTime(times[0].split(" ")[0]);
        queryDTO.setEndTime(times[1]);
        List<ConsoleVoiceRoomDataDTO> result = voiceRoomStatisticDOMapper.getList(queryDTO);
        List<String> roomIds = result.stream().map(ConsoleVoiceRoomDataDTO::getVoiceRoomId).collect(Collectors.toList());
        if (roomIds.isEmpty()) {
            return result;
        }
        List<VoiceRoom> rooms = voiceRoomMapper.listWithRoomIds(roomIds);
        Map<String, String> nameMap = rooms.stream().collect(Collectors.toMap(VoiceRoom::getRoomId, VoiceRoom::getRoomName));
        result.forEach(item -> item.setRoomName(nameMap.getOrDefault(item.getVoiceRoomId(), "")));
        return result;
    }

    @Override
    public Integer countVoiceRoomData(VoiceRoomDataQueryDTO queryDTO) {
        return voiceRoomStatisticDOMapper.getCount(queryDTO);
    }

    @Override
    public HashMap<String, Long> getVoiceRoomStatisticData(VoiceRoomDataQueryDTO queryDTO) {
        HashMap<String, Long> statisticMap = voiceRoomStatisticDOMapper.getStatisticData(queryDTO);
        List<String> tableNameList = CommonUtil.getTableListFromDate(queryDTO.getStartTime(), queryDTO.getEndTime(),
                "user_leave_voice_room");
        List<Long> robotIdList = robotConfigDOMapper.getRobotIdList();
        Long participateCount =  userLeaveVoiceRoomDOMapper.getParticipateCount(queryDTO.getStreamerId(),
                queryDTO.getRebateType(), tableNameList, queryDTO.getStartTime(), queryDTO.getEndTime(), robotIdList);
        statisticMap.put("participate_count",participateCount);

        Long participateCountEx = userLeaveVoiceRoomDOMapper.getParticipateCountEx(queryDTO.getStreamerId(),
                queryDTO.getRebateType(), tableNameList, queryDTO.getStartTime(), queryDTO.getEndTime(), robotIdList);
        statisticMap.put("participate_count_ex", participateCountEx);

        tableNameList = CommonUtil.getTableListFromDate(queryDTO.getStartTime(), queryDTO.getEndTime(),
                "user_gift_voice_room");
        statisticMap.put("send_gift_count",userGiftVoiceRoomDOMapper.getSendGiftCount(queryDTO.getStreamerId(),
                queryDTO.getRebateType(), tableNameList, queryDTO.getStartTime(), queryDTO.getEndTime()));
        return statisticMap;
    }

    @Override
    public VoiceRoomData getVoiceRoomDetailData(VoiceRoomStatisticSearchConditionDTO conditionDTO) {
        VoiceRoomData roomData = new VoiceRoomData();
        HashMap<String, Object> totalRoomNumAndBroadcastDurationMap = getTotalRoomNumAndBroadcastDuration(conditionDTO);
        roomData.setTotalRoomNum((Long) totalRoomNumAndBroadcastDurationMap.get("total_room_num"));
        roomData.setIncreasedRoomNum(getIncreasedRoomNum(conditionDTO));
        roomData.setTotalBroadcastDuration(Long.valueOf(totalRoomNumAndBroadcastDurationMap.get("total_broadcast_duration").toString()));
        HashMap<String, Object> totalAccountInVoiceRoom = getTotalAccountInVoiceRoom(conditionDTO);
        roomData.setTotalAccountNumber((Long) totalAccountInVoiceRoom.get("total_account_number"));
        roomData.setTotalAccountCount((Long) totalAccountInVoiceRoom.get("total_account_count"));
        roomData.setTotalAccountDuration(Long.valueOf(totalAccountInVoiceRoom.get("total_account_duration").toString()));
        if (roomData.getTotalAccountNumber() == 0) {
            roomData.setAverageAccountDuration((long) 0);
        }
        else {
            roomData.setAverageAccountDuration(roomData.getTotalAccountDuration() / roomData.getTotalAccountNumber());
        }

        HashMap<String, Object> sendGiftInfo = getSendGiftInfo(conditionDTO);
        roomData.setSendGiftAccountNumber((Long) sendGiftInfo.get("send_gift_account_number"));
        roomData.setSendGiftAccountCount((Long) sendGiftInfo.get("send_gift_account_count"));
        roomData.setCoinIncome(Long.valueOf(sendGiftInfo.get("coin").toString()));
        roomData.setDiamondIncome(Long.valueOf(sendGiftInfo.get("diamond").toString()));

        roomData.setListCount(streamerDataDOMapper.getCount(conditionDTO));
        List<StreamerDataDO> streamerDataDOList = streamerDataDOMapper.getList(conditionDTO);
        List<VoiceRoomStatisticDTO> voiceRoomStatisticDTOList= new ArrayList<>();
        for(StreamerDataDO streamerDataDO:streamerDataDOList){
            VoiceRoomStatisticSearchConditionDTO tempConditionDTO = new VoiceRoomStatisticSearchConditionDTO();
            tempConditionDTO.setStartTime(dateUtil.GetFormatDate(streamerDataDO.getUpperWheatTime(), "yyyy-MM-dd HH:mm:ss"));
            tempConditionDTO.setEndTime(dateUtil.GetFormatDate(streamerDataDO.getLowerWheatTime(), "yyyy-MM-dd HH:mm:ss"));
            tempConditionDTO.setStreamerId(streamerDataDO.getStreamerId());

            HashMap<String, Object> tempSendGiftInfo = getSendGiftInfo(tempConditionDTO);
            VoiceRoomStatisticDTO voiceRoomStatisticDTO = streamerDataDO.convertVoiceRoomStatisticDTO();
            voiceRoomStatisticDTO.setSendGiftAccountNumber((Long) tempSendGiftInfo.get("send_gift_account_number"));
            voiceRoomStatisticDTO.setSumCoin(Long.valueOf(tempSendGiftInfo.get("coin").toString()));
            voiceRoomStatisticDTO.setSumDiamond(Long.valueOf(tempSendGiftInfo.get("diamond").toString()));
            voiceRoomStatisticDTO.setSendGiftAccountCount((Long) tempSendGiftInfo.get("send_gift_account_count"));

            HashMap<String, Object> tempTotalAccountInVoiceRoom = getTotalAccountInVoiceRoom(tempConditionDTO);
            voiceRoomStatisticDTO.setTotalAccountNumber((Long) tempTotalAccountInVoiceRoom.get("total_account_number"));
            voiceRoomStatisticDTO.setTotalAccountCount((Long) tempTotalAccountInVoiceRoom.get("total_account_count"));
            voiceRoomStatisticDTO.setTotalAccountDuration(Long.valueOf(tempTotalAccountInVoiceRoom.get("total_account_duration").toString()));
            if (voiceRoomStatisticDTO.getTotalAccountNumber() == 0) {
                voiceRoomStatisticDTO.setAverageAccountDuration((long) 0);
            }
            else {
                voiceRoomStatisticDTO.setAverageAccountDuration(
                        voiceRoomStatisticDTO.getTotalAccountDuration() / voiceRoomStatisticDTO.getTotalAccountNumber());
            }

            voiceRoomStatisticDTOList.add(voiceRoomStatisticDTO);
        }
        roomData.setVoiceRoomStatisticDTOS(voiceRoomStatisticDTOList);
        return roomData;
    }

    @Override
    public List<UserUpperVoiceRoomDO> listUserUpperVoiceRoom(VoiceRoomUserUpperQueryDTO voiceRoomUserUpperQueryDTO) {
        String[] times = CommonUtil.setStartTime(voiceRoomUserUpperQueryDTO.getStartTime(),
                voiceRoomUserUpperQueryDTO.getEndTime());
        voiceRoomUserUpperQueryDTO.setStartTime(times[0].split(" ")[0]);
        voiceRoomUserUpperQueryDTO.setEndTime(times[1]);
        List<String> tableList = CommonUtil.getTableListFromDate(voiceRoomUserUpperQueryDTO.getStartTime(),
                voiceRoomUserUpperQueryDTO.getEndTime(),"user_upper_voice_room");
        voiceRoomUserUpperQueryDTO.setTableNameList(tableList);
        return userUpperVoiceRoomDOMapper.listUserUpperVoiceRoom(voiceRoomUserUpperQueryDTO);
    }

    @Override
    public Integer countUserUpperVoiceRoom(VoiceRoomUserUpperQueryDTO voiceRoomUserUpperQueryDTO) {
        return userUpperVoiceRoomDOMapper.countUserUpperVoiceRoom(voiceRoomUserUpperQueryDTO);
    }

    @Override
    public HashMap<String, Long> statisticUserUpperVoiceRoom(VoiceRoomUserUpperQueryDTO voiceRoomUserUpperQueryDTO) {
        HashMap<String, Long> data = new HashMap<>(16);
        data.put("user_upper_number", userUpperVoiceRoomDOMapper.getUserUpperNumber(voiceRoomUserUpperQueryDTO));
        data.put("user_upper_duration", userUpperVoiceRoomDOMapper.getUserUpperDuration(voiceRoomUserUpperQueryDTO));
        return data;
    }

    @Override
    public List<ConsoleVoiceRoomDataDTO> getVoiceRoomDataDailySum(VoiceRoomDataQueryDTO queryDTO) {
        String[] times = CommonUtil.setStartTime(queryDTO.getStartTime(), queryDTO.getEndTime());
        queryDTO.setStartTime(times[0].split(" ")[0]);
        queryDTO.setEndTime(times[1]);
        List<ConsoleVoiceRoomDataDTO> consoleVoiceRoomData = voiceRoomStatisticDOMapper.getListDailySum(queryDTO);
        for (ConsoleVoiceRoomDataDTO data: consoleVoiceRoomData) {
            String targetDate = data.getTargetDate();
            List<String> tableNameList = CommonUtil.getTableListFromDate(targetDate, targetDate,
                    "user_leave_voice_room");
            List<Long> robotIdList = robotConfigDOMapper.getRobotIdList();
            Long participateCount =  userLeaveVoiceRoomDOMapper.getParticipateCount(queryDTO.getStreamerId(),
                    queryDTO.getRebateType(), tableNameList, targetDate, targetDate, robotIdList);
            data.setParticipateCount(Math.toIntExact(participateCount));

            Long participateCountEx = userLeaveVoiceRoomDOMapper.getParticipateCountEx(queryDTO.getStreamerId(),
                    queryDTO.getRebateType(), tableNameList, targetDate, targetDate, robotIdList);
            data.setParticipateCountEx(Math.toIntExact(participateCountEx));

            tableNameList = CommonUtil.getTableListFromDate(targetDate, targetDate,
                    "user_gift_voice_room");
            data.setSendGiftCount(Math.toIntExact(userGiftVoiceRoomDOMapper.getSendGiftCount(queryDTO.getStreamerId(),
                    queryDTO.getRebateType(), tableNameList, targetDate, targetDate)));

        }
        return consoleVoiceRoomData;
    }

    @Override
    public Integer countVoiceRoomDataDailySum(VoiceRoomDataQueryDTO queryDTO) {
        return voiceRoomStatisticDOMapper.getCountDailySum(queryDTO);
    }

    @Override
    public List<ConsoleVoiceRoomPieDataDTO> getVoiceRoomDataPie(VoiceRoomDataQueryDTO queryDTO) {
        String[] times = CommonUtil.setStartTime(queryDTO.getStartTime(), queryDTO.getEndTime());
        queryDTO.setStartTime(times[0].split(" ")[0]);
        queryDTO.setEndTime(times[1]);
        List<ConsoleVoiceRoomPieDataDTO> result;
        if (queryDTO.getStreamerId() != null) {
            List<String> tableNameList = CommonUtil.getTableListFromDate(queryDTO.getStartTime(), queryDTO.getEndTime(),
                    "user_gift_voice_room");
            result = userGiftVoiceRoomDOMapper.getPie(queryDTO.getStreamerId(),
                    queryDTO.getRebateType(), tableNameList, queryDTO.getStartTime(), queryDTO.getEndTime());
        } else {
            result = voiceRoomStatisticDOMapper.getPie(queryDTO);
        }
        if (queryDTO.getStreamerId() != null) {
            List<String> accountIds = result.stream().map(ConsoleVoiceRoomPieDataDTO::getName).collect(Collectors.toList());
            if (accountIds.isEmpty()) {
                return result;
            }
            List<Account> accounts = accountMapper.getNicknameList(accountIds);
            Map<Long, String> nameMap = accounts.stream().collect(Collectors.toMap(Account::getUid, Account::getUserName));
            result.forEach(item -> item.setName(item.getName() + " (" + nameMap.getOrDefault(Long.parseLong(item.getName()), "") + ")"));
        }
        else if (queryDTO.getRebateType() != null) {
            List<String> roomIds = result.stream().map(ConsoleVoiceRoomPieDataDTO::getName).collect(Collectors.toList());
            if (roomIds.isEmpty()) {
                return result;
            }
            List<VoiceRoom> rooms = voiceRoomMapper.listWithRoomIds(roomIds);
            Map<String, String> nameMap = rooms.stream().collect(Collectors.toMap(VoiceRoom::getRoomId, VoiceRoom::getRoomName));
            result.forEach(item -> item.setName(nameMap.getOrDefault(item.getName(), "")));
        }
        int maxSize = 15; // 饼图展示最多展示的个数，之后的汇总为其他
        if (result.size() > maxSize) {
            List<ConsoleVoiceRoomPieDataDTO> startPieData = result.subList(0, maxSize);
            List<ConsoleVoiceRoomPieDataDTO> endPieData = result.subList(maxSize, result.size());
            Long sum_profit = endPieData.stream().mapToLong(ConsoleVoiceRoomPieDataDTO::getValue).sum();
            ConsoleVoiceRoomPieDataDTO otherPieData = new ConsoleVoiceRoomPieDataDTO();
            otherPieData.setValue(sum_profit);
            otherPieData.setName("其他");
            startPieData.add(otherPieData);
            return startPieData;
        }
        return result;
    }

    private JSONObject getSeriesItem(String matchTypeName, Map<String,Long> tempMap)
    {
        JSONObject seriesItem = new JSONObject();
        seriesItem.put("name", matchTypeName);
        seriesItem.put("type", "line");
        JSONArray seriesItemDataList = new JSONArray();
        for(String key : tempMap.keySet()) {
            seriesItemDataList.add(tempMap.get(key));
        }
        seriesItem.put("data", seriesItemDataList);
        JSONObject areaStyle = JSONObject.parseObject("{normal: {}}");
        seriesItem.put("areaStyle", areaStyle);
        return seriesItem;
    }

    private JSONObject getLines(String startTime, String endTime, List <ConsoleVoiceRoomChartDataDTO> voiceRoomData) {
        JSONObject legend = new JSONObject();
        JSONArray legendList = new JSONArray();
        legend.put("data",legendList);

        JSONArray xAxis = new JSONArray();
        List<String> dateList = dateUtil.getnDayList(startTime, endTime);
        JSONObject xAxisData = new JSONObject();
        xAxisData.put("data", JSONArray.parseArray(JSON.toJSONString(dateList)));
        xAxis.add(xAxisData);

        JSONArray series = new JSONArray();
        boolean isFirst = true;
        String lastType = null;
        Map<String,Long>  tempMap = null;
        for (ConsoleVoiceRoomChartDataDTO data: voiceRoomData)
        {
            if(isFirst)
            {
                tempMap = dateUtil.GetNDaysMap(startTime,endTime);
                lastType = data.getType();
                isFirst = false;
            }
            if (!lastType.equals(data.getType()))
            {

                legendList.add(lastType);
                series.add(getSeriesItem(lastType, tempMap));
                lastType = data.getType();
                tempMap = dateUtil.GetNDaysMap(startTime,endTime);
            }
            tempMap.put(data.getName(), data.getValue());
        }
        if(lastType !=null)
        {
            legendList.add(lastType);
            series.add(getSeriesItem(lastType, tempMap));
        }
        JSONObject resObj = new JSONObject();
        resObj.put("legend", legend);
        resObj.put("xAxis", xAxis);
        resObj.put("series", series);
        return resObj;
    }

    @Override
    public JSONObject getVoiceRoomDataLine(VoiceRoomDataQueryDTO queryDTO) {
        String[] times = CommonUtil.setStartTime(queryDTO.getStartTime(), queryDTO.getEndTime());
        queryDTO.setStartTime(times[0].split(" ")[0]);
        queryDTO.setEndTime(times[1]);
        List<ConsoleVoiceRoomChartDataDTO> voiceRoomData = voiceRoomStatisticDOMapper.getLine(queryDTO);
        return getLines(queryDTO.getStartTime(), queryDTO.getEndTime(), voiceRoomData);
    }

}
